﻿/*------------------------------------------------------------------------

CAMERA.HPP v1.1.3

Copyright 楊志賢 CxxlMan, 2012 - 2013
All Rights Reserved

依不同平台的實作應包含有局部空間的轉換矩陣，可藉取得其反矩陣作為觀察座標矩
陣。另外還應包含 Viewport 和投影矩陣的設定功能，以及掛上一個 IRenderPipe

在 Render 中可設定多個 ICamera，在渲染循環廻圈中依次為各個 ICamera 做
各別物件串列的渲染

------------------------------------------------------------------------*/

#if !defined(__CAMERA_HPP_Cxxl3D)
#define __CAMERA_HPP_Cxxl3D

#include <CENTRALIZEDMGR.HPP>
#include "Sys\MATH.HPP"
#include "IREBDERPIPE.HPP"
#include "C3DNODE.HPP"
#include "MATRIX.HPP"
#include "CSMART_PTR.HPP"

// 元件介面的識別碼
#define ICamera_ClassID L"3F2488FF-C4C3-4e30-AFED-8F280C83F1DE"

namespace Cxxl3D
{

class ICamera:public IC3D_NodeHost
{
  CxxlMan::Smart_Ptr<IRenderPipe> m_IRenderPipe_Ptr;

protected:

  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F) = 0
  {
    if(F != NULL && IC3D_NodeHost::Ref(F))
      return true;
    else
      return false;
  }

public:
  // Constructor
  ICamera()
    :cxxlObject(CxxlMan::Spirit_Easy),
    cxxlPreserve2(ICamera_ClassID),
    m_IRenderPipe_Ptr(NULL,this)
  {}

  // Destructor
  virtual ~ICamera()
  {}

  // 取得觀察座標空間的轉換矩陣
  virtual CxxlMan::CSmart_Ptr<Matrix4x4> cxxlFASTCALL GetViewMatrix() const = 0;


  // 指定 Virwport 的範圍，值在 0 ~ 1 之間，若未指定，實作應內定(0,0)-(1,1)
  virtual void cxxlFASTCALL SetViewport(float Left, float Top, float Right, float Bottom) = 0;
  // 取得 Virwport 的範圍
  virtual void cxxlFASTCALL GetViewport(float &Left, float &Top, float &Right, float &Bottom) const = 0;


  // 設定/取得 Perspective 投影模式
  // fovy = 垂直方向的視角
  // z_hear = 鏡頭可以看到的最近距離
  // z_far = 鏡頭可以看到的最遠距離
  virtual void cxxlFASTCALL SetPerspective(C3D_FLOAT fovy, C3D_FLOAT z_near, C3D_FLOAT z_far) = 0;
  // 若不是 Perspective 回覆 false
  virtual bool cxxlFASTCALL GetPerspective(C3D_FLOAT &fovy, C3D_FLOAT &z_near, C3D_FLOAT &z_far) = 0;


  // 設定/取得 Ortho 投影模式
  // h = 鏡頭垂直方向可以看到的範圍
  // z_hear = 鏡頭可以看到的最近距離
  // z_far  = 鏡頭可以看到的最遠距離
  virtual void cxxlFASTCALL SetOrtho(C3D_FLOAT h, C3D_FLOAT z_near, C3D_FLOAT z_far) = 0;
  // 若不是 Ortho 回覆 false
  virtual bool cxxlFASTCALL GetOrtho(C3D_FLOAT &h, C3D_FLOAT &z_near, C3D_FLOAT &z_far) = 0;


  // 若採用 Perspective 投影模式回覆 true
  virtual bool cxxlFASTCALL isPerspective() = 0;

  void cxxlFASTCALL SetIRenderPipe(const CxxlMan::Smart_Ptr<IRenderPipe> &IRenderPipe_Arg)
  {
    csPreserve.Enter();
    m_IRenderPipe_Ptr = IRenderPipe_Arg;
    csPreserve.Leave();
  }

  CxxlMan::Smart_Ptr<IRenderPipe> cxxlFASTCALL GetIRenderPipe()
  {
    CxxlMan::CriticalSecHandle AutoCSH(csPreserve);

    return m_IRenderPipe_Ptr;
  }




public:

  // 取得 ICamera 物件，失敗傳回 NULL
  static CxxlMan::Smart_Ptr<ICamera> cxxlFASTCALL Create()
  {
    return CxxlMan::Preserve2_Cast<ICamera>( CxxlMan::cxxlCM_GetElement(ICamera_ClassID, CXXL3DDEFAULTGROUP) );
  }

  // 從永存資料產生 ICamera 物件並取回永存資料
  // 失敗傳回 NULL
  static CxxlMan::Smart_Ptr<ICamera> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &BackupName, const CxxlMan::Smart_Ptr<CxxlMan::IcxxlStorage> &IcxxlStorage_Arg)
  {
    CxxlMan::Smart_Ptr<cxxlPreserve2> cxxlPreserve2_Ptr(NULL);
    CxxlMan::REGENERARETURN_TYPE rt = cxxlCM_Regenera(cxxlPreserve2_Ptr, BackupName, IcxxlStorage_Arg, true);
    if(rt == CxxlMan::Regenera_Success)
      return CxxlMan::Smart_Cast<ICamera>(cxxlPreserve2_Ptr);
    return NULL;
  }


  friend class CxxlMan::IcxxlStorage;
  friend class CxxlMan::Smart_Ptr<ICamera>;
};

// 初始化，這裡只做元件註冊
inline void ICamera_Init()
{
  CxxlMan::cxxlCM_ElementReg(ICamera_ClassID, CXXL3DDEFAULTGROUP, L"C3dLib.dll");
}


}   /* namespace Cxxl3D */
#endif
